package work.mediway.mdm.biz.service.patient.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import work.mediway.mdm.core.page.QueryRequest;
import work.mediway.mdm.core.exception.DataException;
import work.mediway.mdm.biz.dto.patient.PatientDTO;
import work.mediway.mdm.biz.dto.patient.PatientSuspectDTO;
import work.mediway.mdm.biz.entity.patient.PaSuspectPatient;
import work.mediway.mdm.biz.entity.patient.PatientConfig;
import work.mediway.mdm.biz.helper.SuspectHelper;
import work.mediway.mdm.biz.mapper.patient.PaSuspectPatientMapper;
import work.mediway.mdm.biz.service.patient.PaPatientService;
import work.mediway.mdm.biz.service.patient.PaSuspectPatientService;
import work.mediway.mdm.biz.service.patient.PatientConfigService;
import work.mediway.mdm.biz.vo.patient.PatientDetailVO;
import work.mediway.mdm.biz.vo.patient.PatientListVO;
import work.mediway.mdm.biz.vo.patient.SuspectPatientDetailVO;
import work.mediway.mdm.biz.vo.patient.SuspectPatientListVO;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2020/12/21
 */
@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class PaSuspectPatientServiceImpl extends ServiceImpl<PaSuspectPatientMapper, PaSuspectPatient> implements PaSuspectPatientService {

    @Autowired
    private PatientConfigService patientConfigService;
    @Autowired
    private PaPatientService patientService;

    @Override
    public Page<SuspectPatientListVO> pageSuspectPatient(PatientSuspectDTO suspectDTO, QueryRequest queryRequest) {
        Page<SuspectPatientListVO> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        page.setOrders(OrderItem.descs("lastUpdateDate"));
        page.setRecords(this.baseMapper.pageSuspectPatient(page, suspectDTO));
        page.getRecords().forEach(i -> i.setLastUpdateDateTime(StrUtil.join(" ", i.getLastUpdateDate(), i.getLastUpdateTime())));
        return page;
    }

    @Override
    public List<SuspectPatientDetailVO> suspectPatientDetail(String patPatientId) {
        return this.baseMapper.suspectPatientDetail(patPatientId);
    }

    @Override
    public List<PaSuspectPatient> computeSuspect(String majorPatPatientId, String minorPatPatientIds) {
        if (StrUtil.isBlank(majorPatPatientId)) {
            throw new DataException(StrUtil.format("主患者Id = 【{}】不能为空", majorPatPatientId));
        }
        List<PaSuspectPatient> result = CollUtil.newArrayList();
        // 查询主患者信息
        PatientDetailVO majorPatientDetail = this.patientService.getPatientDetail(majorPatPatientId, null);
        // 查询权重信息
        Map<String, String> configs = this.patientConfigService.list()
                .stream().collect(Collectors.toMap(PatientConfig::getIndexCode, PatientConfig::getIndexWeight));
        // 如果主患者不为空，次患者为空，则计算该患者的所有相似患者
        if (StrUtil.isBlank(minorPatPatientIds)) {
            log.info("将查找患者Id = 【{}】的相似患者", majorPatPatientId);
            PatientDTO patientDTO = new PatientDTO();
            // 身份证号相同的所有患者
            patientDTO.setPatPatientCardNo(majorPatientDetail.getPatPatientCardNo());
            Page<PatientListVO> patientListByCard = this.patientService.pagePatientList(null, patientDTO);
            if (CollUtil.isNotEmpty(patientListByCard.getRecords())) {
                for (PatientListVO cardRecord : patientListByCard.getRecords()) {
                    if (!StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPatientId(), cardRecord.getPatPatientId())) {
                        SuspectHelper.computeSuspect(configs, majorPatientDetail, BeanUtil.copyProperties(cardRecord, PatientDetailVO.class), result);
                    }
                }
            }
            patientDTO.clear();
            patientDTO.setPatPatientName(majorPatientDetail.getPatPatientName());
            Page<PatientListVO> patientListByName = this.patientService.pagePatientList(null, patientDTO);
            if (CollUtil.isNotEmpty(patientListByName.getRecords())) {
                for (PatientListVO record : patientListByName.getRecords()) {
                    if (!StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPatientId(), record.getPatPatientId())) {
                        SuspectHelper.computeSuspect(configs, majorPatientDetail, BeanUtil.copyProperties(record, PatientDetailVO.class), result);
                    }
                }
            }
            patientDTO.clear();
            patientDTO.setPatPhone(majorPatientDetail.getPatPhone());
            Page<PatientListVO> patientListByPhone = this.patientService.pagePatientList(null, patientDTO);
            if (CollUtil.isNotEmpty(patientListByPhone.getRecords())) {
                for (PatientListVO record : patientListByPhone.getRecords()) {
                    if (!StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPatientId(), record.getPatPatientId())) {
                        SuspectHelper.computeSuspect(configs, majorPatientDetail, BeanUtil.copyProperties(record, PatientDetailVO.class), result);
                    }
                }
            }
            return result;
        }

        List<String> minors = StrUtil.splitTrim(minorPatPatientIds, StringPool.PIPE);
        log.info(StrUtil.format("将计算相似患者数量：【{}】, 主患者Id = 【{}】, 次患者Id = 【{}】", minors.size(), majorPatPatientId, minors.toString()));
        if (majorPatientDetail == null) {
            throw new DataException("未查询到主患者平台Id = 【" + majorPatPatientId + "】的信息");
        }
        for (String minor : minors) {
            // 查询次患者信息
            PatientDetailVO minorPatientDetail = this.patientService.getPatientDetail(minor, null);
            if (minorPatientDetail == null) {
                throw new DataException("未查询到次患者平台Id = 【" + majorPatPatientId + "】的信息");
            }
            // 计算两个患者的相似信息，返回两条完整的数据
            SuspectHelper.computeSuspect(configs, majorPatientDetail, minorPatientDetail, result);
            if (result.size() < 1) {
                return result;
            }
            LambdaQueryWrapper<PaSuspectPatient> queryWrapper = Wrappers.lambdaQuery(PaSuspectPatient.class);
            // 主患者的所有相似患者，记录还存在，可以直接取然后存入
            List<PaSuspectPatient> major = this.list(queryWrapper.eq(PaSuspectPatient::getSuspectPatPatientId, majorPatPatientId));
            if (CollUtil.isNotEmpty(major)) {
                for (PaSuspectPatient patient : major) {
                    patient.setSuspectPatPatientId(patient.getSuspectRelPatPatientId());
                    patient.setSuspectRelPatPatientId(majorPatPatientId);
                    result.add(patient);
                }
            }
            // 次患者患者的所有相似患者，记录已删除，可以直接查询主患者相似患者信息然后计算
            queryWrapper.clear();
            List<PaSuspectPatient> majorSuspectList = this.list(queryWrapper.eq(PaSuspectPatient::getSuspectPatPatientId, majorPatPatientId));
            if (CollUtil.isNotEmpty(major)) {
                List<String> patIds = CollUtil.newArrayList();
                for (PaSuspectPatient suspectPatient : majorSuspectList) {
                    patIds.add(suspectPatient.getSuspectRelPatPatientId());
                }
                PatientDTO patientDTO = new PatientDTO();
                patientDTO.setPatPatientIds(patIds);
                Page<PatientListVO> relPatients = this.patientService.pagePatientList(new QueryRequest(), patientDTO);
                for (PatientListVO record : relPatients.getRecords()) {
                    SuspectHelper.computeSuspect(configs, minorPatientDetail, BeanUtil.copyProperties(record, PatientDetailVO.class), result);
                }
            }
        }
        return result;
    }

    @Override
    public void saveSuspect(List<PaSuspectPatient> suspectPatients) {
        for (PaSuspectPatient suspect : suspectPatients) {
            if (StrUtil.equalsAnyIgnoreCase(suspect.getSuspectPatPatientId(), suspect.getSuspectRelPatPatientId())) {
                return;
            }
            LambdaQueryWrapper<PaSuspectPatient> queryWrapper = Wrappers.lambdaQuery(PaSuspectPatient.class)
                    .eq(PaSuspectPatient::getSuspectPatPatientId, suspect.getSuspectPatPatientId())
                    .eq(PaSuspectPatient::getSuspectRelPatPatientId, suspect.getSuspectRelPatPatientId());
            PaSuspectPatient one = this.getOne(queryWrapper);
            if (ObjectUtil.isNotEmpty(one)) {
                LambdaUpdateWrapper<PaSuspectPatient> updateWrapper = Wrappers.lambdaUpdate(PaSuspectPatient.class)
                        .eq(PaSuspectPatient::getSuspectPatPatientId, suspect.getSuspectPatPatientId())
                        .eq(PaSuspectPatient::getSuspectRelPatPatientId, suspect.getSuspectRelPatPatientId());
                this.update(suspect, updateWrapper);
            } else {
                this.save(suspect);
            }
        }
    }
}